home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / scheme / pcscheme / geneva / sources.exe / SOURCES / INLINE / SNOW.ASM < prev    next >
Encoding:
Assembly Source File  |  1992-11-24  |  12.8 KB  |  489 lines

  1. ;* SNOW.ASM
  2. ;************************************************************************
  3. ;*                                    *
  4. ;*        PC Scheme/Geneva 4.00 Borland TASM code            *
  5. ;*                                    *
  6. ;* (c) 1985-1988 by Texas Instruments, Inc. See COPYRIGHT.TXT        *
  7. ;* (c) 1992 by L. Bartholdi & M. Vuilleumier, University of Geneva    *
  8. ;*                                    *
  9. ;*----------------------------------------------------------------------*
  10. ;*                                    *
  11. ;*        Fractal snowflakes for a 386 VGA IBM PC            *
  12. ;*                                    *
  13. ;*----------------------------------------------------------------------*
  14. ;*                                    *
  15. ;* Created by: Larry Bartholdi        Date: 1991            *
  16. ;* Revision history:                            *
  17. ;* - 18 Jun 92:    Renaissance (Borland Compilers, ...)            *
  18. ;*                                    *
  19. ;*                    ``In nomine omnipotentii dei''    *
  20. ;************************************************************************
  21. IDEAL
  22. %PAGESIZE    66, 132
  23. %TITLE    "Fractal snowflakes in assemler"
  24.  
  25. ; use: (snowflake #size #x #y #angle #level #first)
  26. ; all arguments are numbers, but nothing is checked for.
  27. ; typically this code should be interfaced through a nice Scheme
  28. ; layer that would check the arguments, center the figure,
  29. ; scale it, etc., all stuff best done in a high level language.
  30. ;
  31. ; a good demo example is (snowflake 400 200 10 1 6 1)
  32.  
  33. ;PROGRAMMER'S NOTE:
  34. ;
  35. ; numbers are represented in two formats:
  36. ; word (16_bit) to represent integer quantities
  37. ; dword (32_bit) to represent fixed-point quantities
  38. ; you will see many 'shl eax, 10' in the code. these represent
  39. ; conversions from one notation to the other.
  40.  
  41. ;*****************************************************************************
  42. ;* assembler directives
  43. ;*****************************************************************************
  44. P386
  45. INCLUDE    "inline.ash"
  46.  
  47. ;*****************************************************************************
  48. ;* a few useful constants
  49. ;*****************************************************************************
  50. XSIZE    =    640
  51. YSIZE    =    480
  52. ANGLES    =    12
  53.  
  54. VGA_LATCH    =    03dah
  55. VGA_COLOR    =    03c8h
  56. VGA_PALETTE    =    03c0h
  57. VGA_PAGE    =    03cdh
  58. VGA_MODE    =    03ceh
  59. VGA_MASK    =    03c4h
  60. VGA_SEG        =    0a000h
  61.  
  62. ;*****************************************************************************
  63. ;* system macros
  64. ;*****************************************************************************
  65. MACRO    setmode    mode        ;; set video mode
  66.     mov    ax, mode
  67.     int    10h
  68. ENDM
  69.  
  70. MACRO    getchar                   ;; get char from keyboard in AX
  71.     mov    ah, 0
  72.     int    16h
  73. ENDM
  74.  
  75. startinline    SNOWFLAKE, 6
  76.     jmp    main
  77.  
  78. ;*****************************************************************************
  79. ;* data definitions
  80. ;*****************************************************************************
  81. len    dd    ?
  82. x    dd    ?
  83. y    dd    ?
  84. angle    dw    ?
  85. level    dw    ?
  86.  
  87.     ; sines and cosines of multiples of 2\pi / ANGLES
  88.  
  89. sin    dd    0h,    8000h,    0ddb4h    ; the two tables are interleaved
  90. cos    dd    10000h,    0ddb4h,    8000h    ; for maximum space saving
  91.     dd    0h,    -8000h,    -0ddb4h
  92.     dd    -10000h,-0ddb4h,-8000h    ; end of sine
  93.     dd    0h,    8000h,    0ddb4h    ; end of cosine
  94.  
  95. label    palette    BYTE
  96.     db    04h, 0ah, 10h, 15h
  97.     db    1ah, 1fh, 23h, 27h
  98.     db    2bh, 2fh, 32h, 35h
  99.     db    38h, 3bh, 3dh, 3fh
  100.  
  101. ;*****************************************************************************
  102. ;* entry point
  103. ;*****************************************************************************
  104. PROC    main    FAR
  105.     ; main procedure
  106.     ; sets up everything 4 the recursion
  107.     ; note in particular that the code is fully relocatable,
  108.     ; that is, all accesses to memory are done relative to IP
  109.     ; thus the followin code:
  110.  
  111.     ; call: (snowflake length x y angle level flag)
  112.  
  113.     call    @@next
  114. @@next:
  115.     pop    bp
  116.     sub    bp, OFFSET @@next
  117.                 ; substract the disk-image address, so
  118.                 ; we now have the difference between
  119.                 ; a .COM image and what is actually loaded
  120.     ; !! FROM NOW ON, ALL ADDRESSING SHOULD BE DONE RELATIVE TO DS:BP !!
  121.  
  122.     movzx    eax, [reg1.disp]; get the passed length
  123.     shl    eax, 10h
  124.     mov    [cs:bp+len], eax
  125.     movzx    eax, [reg2.disp]; get the passed x0
  126.     shl    eax, 10h
  127.     mov    [cs:bp+x], eax
  128.     movzx    eax, [reg3.disp]; get the passed y0
  129.     shl    eax, 10h
  130.     mov    [cs:bp+y], eax
  131.     mov    ax, [reg4.disp]    ; get the passed angle
  132.     mov    [cs:bp+angle], ax
  133.     mov    ax, [reg5.disp]    ; get the passed level
  134.     mov    [cs:bp+level], ax
  135.  
  136.     cmp    [reg6.disp], 0    ; is flag on ?
  137.     je    @@skip
  138.     setmode    12h        ; VGA 640x480
  139.     call    setpalette
  140. @@skip:
  141. REPT    3
  142.     call    recurse        ; draw a kinked line
  143.     call    turnright    ; and turn right 120^o
  144.     call    turnright
  145. ENDM
  146.     retf
  147. ENDP    main
  148.  
  149. ;*****************************************************************************
  150. ;* the real stuff
  151. ;*****************************************************************************
  152. PROC    recurse
  153.     ; draw a kinked line from (x,y), direction len*cis(angle)
  154.     ; if level=0 draw ____ (total length len)
  155.     ;       else draw _/\_ (each segment's length len/3)
  156.     ; assumes: x, y, angle, level contain appropriate data
  157.     ; returns: nothing
  158.     ;  sideff: none
  159.     ;   trash: ax, bx, dx
  160.     ;  tested: LB, 6-XII-91 (Passed)
  161.  
  162.     cmp    [cs:bp+level], 1
  163.     je    line        ; fall through line (tail-recursive!)
  164.  
  165.     push    [cs:bp+len]    ; save 'em, 'cause we'll directly modify 'em
  166.                 ; for the recursion; beware of roundoffs !
  167.  
  168.     dec    [cs:bp+level]
  169.     mov    eax, [cs:bp+len]
  170.     cdq
  171.     mov    ebx, 3
  172.     div    ebx
  173.     mov    [cs:bp+len], eax
  174.  
  175.     call    recurse        ; recursively draw the line
  176.     call    turnleft
  177.     call    recurse
  178.     call    turnright
  179.     call    turnright
  180.     call    recurse
  181.     call    turnleft
  182.     call    recurse
  183.  
  184.     pop    [cs:bp+len]
  185.     inc    [cs:bp+level]
  186.     ret
  187. ENDP    recurse
  188.  
  189. PROC    line
  190.     ; draw a straight line from (x,y), direction len*cis(angle)
  191.     ; using a simple anti-aliasing technique
  192.     ; to improve resolution
  193.     ; assumes: x, y, angle contain appropriate data
  194.     ;    makes usage of sine and cosine tables
  195.     ; returns: nothing
  196.     ;  sideff: updates x and y
  197.     ;   trash: eax, ebx, ecx, edx, esi, edi
  198.     ;  tested: LB, 6-XII-91 (Passed)
  199.  
  200.     mov    di, [cs:bp+angle]     ; get angle
  201.     shl    di, 2        ; make it a dword index
  202.     mov    ecx, [cs:bp+len]
  203.     shr    ecx, 0ah    ; we now have fixed-point, with a 6-bits
  204.                 ; fractional part (to avoid precision losses)
  205.     adc    ecx, 0
  206.     mov    edx, ecx
  207.     imul    ecx, [cs:bp+cos+di]    ; ecx = \Delta_x
  208.     imul    edx, [cs:bp+sin+di]    ; edx = \Delta_y
  209.  
  210.     sar    ecx, 6        ; shift out the remaining 6 bits
  211.     adc    ecx, 0        ; round up
  212.     sar    edx, 6
  213.     adc    edx, 0        ; and we again have legal (16-bit fraction)
  214.                 ; fixed-point numbers
  215.  
  216.     movzx    ebp, bp        ; assume we have dx > dy.
  217.                 ; we use the 16 high bits of ebp
  218.                 ; to store the orientation
  219.     mov    esi, [cs:bp+x]    ; get (x,y) in (esi,edi)
  220.     mov    edi, [cs:bp+y]
  221.     add    [cs:bp+x], ecx    ; and update the coordinates
  222.     add    [cs:bp+y], edx
  223.     mov    eax, ecx
  224.     or    eax, eax
  225.     jg    @@xpositive
  226.     neg    eax        ; eax is abs(\Delta_x)
  227. @@xpositive:
  228.     mov    ebx, edx
  229.     or    ebx, ebx
  230.     jg    @@ypositive
  231.     neg    ebx        ; ebx is abs(\Delta_y)
  232. @@ypositive:
  233.     ; we now have (esi,edi) = starting point
  234.     ;    (ecx,edx) = \Delta
  235.     ;    (eax,ebx) = abs(\Delta)
  236.  
  237.     cmp    eax, ebx    ; is dx > dy ?
  238.     ja    @@goodslope
  239.     xchg    esi, edi    ; if not, swap all _x and _y
  240.     xchg    eax, ebx    ; so the slope is -1 <= ... <= 1
  241.     xchg    ecx, edx
  242.     add    ebp, 10000h    ; and notify you did it, so the plot
  243.                 ; routine can unswap x and y
  244. @@goodslope:
  245.     or    ecx, ecx    ; is the 'x' increment positive ?
  246.     jg    @@left2right
  247.     add    esi, ecx    ; else scan from right to left
  248.     neg    ecx        ; negate the increment
  249.     add    edi, edx
  250.     neg    edx        ; and change the other coordinate
  251. @@left2right:
  252.     ; we may now loop from esi to esi+ecx
  253.  
  254.     xor    eax, eax
  255.     shrd    eax, edx, 10h
  256.     sar    edx, 10h    ; eax:edx (64_bit) is set to 10000 * dy
  257.     idiv    ecx        ; now eax contains 10000 * dy/dx, that is,
  258.                 ; y_increment
  259.     mov    edx, eax    ; put it in edx
  260.     shr    ecx, 10h    ; make ecx a loop counter
  261.                 ; by keeping the integer part of \Delta_x
  262.     inc    cx        ; and round up
  263. @@loop:
  264.     call    plot    ; plot at (esi,edi)
  265.     add    esi, 10000h
  266.     add    edi, edx
  267.     loop    @@loop
  268.     ret    ; whew ! we did it !
  269. ENDP    line
  270.  
  271. PROC    plot
  272.     ; plot point at (esi,edi)
  273.     ; where these 32-bit registers should be shifted left by 16
  274.     ; to yield pixel coordinates. This actually is fixed-point
  275.     ; arithmetic, necessary to plot at non-integer pixel coordinates
  276.     ; (that is the idea of anti-aliasing).
  277.     ; 
  278.     ; assumes: esi = x/y-coor, edi = y/x-coor, orientation
  279.     ; returns: nothing
  280.     ;  sideff: writes in video memory
  281.     ;   trash: none
  282.     ;  tested: LB, 16-XII-91
  283.  
  284.     pushad            ; save the stuff
  285.  
  286.     mov    ebx, ebp
  287.     shr    ebx, 10h    ; get high word of ebp = orientation
  288.                 ; in bx
  289.  
  290.     shr    esi, 10h
  291.     adc    si, 0        ; now si is integer 'x' coordinate
  292.     mov    eax, edi
  293.     shr    edi, 10h    ; edi is integer 'y' coordinate
  294.                 ; note: DON'T round up !
  295.     shr    eax, 0ch
  296.     and    ax, 0fh        ; ax [0-f] is fractional part.
  297.                 ; put color ax @ (si,di+1)
  298.                 ; and color !ax @ (si,di)
  299.     inc    di        ; first put next
  300.     or    bx, bx        ; did we swap x & y ?
  301.     jz    @@xy1        ; nope
  302.     xchg    si, di        ; yup. unswap
  303. @@xy1:
  304.     call    putpoint     ; and put a point
  305.     or    bx, bx        ; did we swap x & y ?
  306.     jz    @@xy2        ; nope
  307.     dec    si        ; previous x
  308.     inc    di        ; will be undone by next instruction
  309. @@xy2:
  310.     dec    di        ; previous y
  311.     not    ax
  312.     and    ax, 0fh        ; complement the color
  313.     call    putpoint    ; put the other point
  314.     popad            ; restore the stuff
  315.     ret
  316. ENDP    plot
  317.  
  318. PROC    putpoint
  319.     ; adds the color in al to the point at (si,di)
  320.     ; if the sum of both colors exceeds 0f, leave 0f
  321.     ;
  322.     ; assumes: si = x_cor, di = y_cor, al = color
  323.     ; returns: nothing
  324.     ;  sideff: writes directly in the VGA memory; writes directly
  325.     ;    to the video adapter's ports
  326.     ;   trash: none
  327.     ;  tested: LB, 12-XII-91
  328.  
  329.     push    es            ; save the stuff
  330.     pushad
  331.     push    ax            ; save the color
  332.  
  333.     mov    ax, VGA_SEG        ; set segment to VGA ram 
  334.     mov    es, ax
  335.  
  336.     mov    eax, XSIZE shr 3    ; BYTEs per row
  337.     mul    edi            ; times Y
  338.     movzx    ebx, si
  339.     shr    ebx, 3
  340.     add    eax, ebx        ; plus X / 8
  341.     mov    di, ax            ; save it as a pointer
  342.     shr    eax, 10h        ; get page number
  343.     and    al, 0fh            ; mask is useless...
  344.     mov    ah, al
  345.     shl    ah, 4
  346.     or    al, ah            ; transfer to both nibbles
  347.     mov    dx, VGA_PAGE
  348.     out    dx, al            ; write to page register
  349.  
  350.     ; now get the current color
  351.  
  352.     mov    cx, si
  353.     and    cx, 7                  ; keep 3 bits
  354.     mov    bx, 0080h
  355.     shr    bx, cl            ; now bx is the mask
  356.     push    bx            ; save the mask. it will be useful
  357.                     ; later.
  358.     neg    cl
  359.     add    cl, 7-3            ; complement the mask, substract 3
  360.     and    cl, 7            ; again keep 3 bits
  361.     mov    ax, 0304h        ; loop 3+1 times, request = 4
  362.     mov    dx, VGA_MODE
  363. @@loop:
  364.     out    dx, ax            ; set to color plane ah
  365.     mov    ch, [BYTE es:di]    ; get the color
  366.     and    ch, bl            ; keep one bit
  367.     ror    ch, cl            ; ror by cl, so we don't lose 
  368.                     ; anything though carrying out
  369.     or    bh, ch            ; and set this bit in result
  370.     inc    cl            ; get next bit
  371.     dec    ah            ; in previous plane
  372.     jns    @@loop            ; loop
  373.     
  374.     ; we now have bh = color
  375.     ; write it back, adding the requested color
  376.  
  377.     pop    ax            ; pop back the mask in al
  378.     pop    cx            ; and the color in cl
  379.     add    bh, cl            ; add both colors
  380.     cmp    bh, 10h            ; 2 big ?
  381.     jb    @@ok            ; nope
  382.     mov    bh, 0fh            ; yup. back to 0f (maximum value)
  383. @@ok:
  384.     mov    ah, al            ; move the mask to ah
  385.     mov    al, 08h            ; request = 8
  386.     mov    dx, VGA_MODE
  387.     out    dx, ax            ; set mode to write, pixel X & 7
  388.  
  389.     mov    ax, 3
  390.     out    dx, ax                  ; ???
  391.     mov    dx, VGA_MASK
  392.     mov    ax, 0f02h
  393.     out    dx, ax            ; write mask = ALL, mode 2
  394.     mov    ah, [BYTE es:di]    ; set latch registers
  395.     mov    [BYTE es:di], 0        ; clear the pixel
  396.     mov    ah, bh            ; get color
  397.     out    dx, ax            ; write the color            
  398.     mov    ah, [BYTE es:di]    ; set latch
  399.     mov    [BYTE es:di], 0ffh    ; and set these pixels
  400.     mov    ah, 0fh
  401.     out    dx, ax            ; put back a standard color
  402.     mov    dx, VGA_MODE
  403.     mov    ax, 0ff08h
  404.     out    dx, ax            ; put back standard mode and pixel
  405.  
  406.     popad                ; restore regs
  407.     pop    es
  408.     ret                ; home sweet home
  409. ENDP    putpoint
  410.  
  411. PROC    setpalette
  412.     ; sets the graphical palette to grey tones
  413.     ; so we can plot using anti-aliasing
  414.     ;
  415.     ; assumes: palette and paltable
  416.     ; returns: nothing
  417.     ;  sideff: directly writes to the VGA card
  418.     ;   trash: ax, cx, dx, si
  419.     ;  caveat: clears interrupts
  420.     ;  tested: LB, 21-VIII-92
  421.  
  422.     cli
  423.  
  424.     mov    dx, VGA_LATCH        ; magic ?
  425.     in    al, dx
  426.  
  427.     mov    dx, VGA_COLOR
  428.     mov    al, 0            ; starting at color 0
  429.     out    dx, al
  430.     inc    dx
  431.  
  432.     lea    si, [bp+palette]
  433.     mov    cx, 10h            ; 10h colors in mode 640x480
  434. @@loop1:
  435.     lods    [BYTE cs:si]
  436.     out    dx, al            ; output the r,g,b (all the same)
  437.     out    dx, al
  438.     out    dx, al
  439.     loop    @@loop1
  440.  
  441.     mov    dx, VGA_PALETTE
  442.     mov    al, 0
  443.     mov    cx, 10h
  444. @@loop2:
  445.     out    dx, al
  446.     out    dx, al
  447.     inc    al
  448.     loop    @@loop2
  449.     mov    al, 11h            ; set overscan color
  450.     out    dx, al
  451.     mov    al, 0            ; to 0
  452.     out    dx, al
  453.     mov    al, 20h            ; notify end of palette
  454.     out    dx, al
  455.  
  456.     sti
  457.     ret
  458. ENDP    setpalette
  459.  
  460. PROC    turnright
  461.     ; moves the pointer's direction \pi/3 to the right
  462.     ; note: angles are represented as multiples of \pi/3,
  463.     ; in the CW (i.e., unofficial) manner. This is because
  464.     ; the sine tables, ... are defined for CCW orientations,
  465.     ; but the display is top-down reversed !
  466.  
  467.     mov    ax, [cs:bp+angle]
  468.     add    ax, ANGLES/6    ; turn right 2\pi / 6
  469.     cmp    ax, ANGLES
  470.     jb    @@cont
  471.     sub    ax, ANGLES
  472. @@cont:
  473.     mov    [cs:bp+angle], ax
  474.     ret
  475. ENDP    turnright
  476.  
  477. PROC    turnleft
  478.     mov    ax, [cs:bp+angle]
  479.     sub    ax, ANGLES/6
  480.     jnb    @@cont
  481.     add    ax, ANGLES
  482. @@cont:
  483.     mov    [cs:bp+angle], ax
  484.     ret
  485. ENDP    turnleft
  486.  
  487. endinline
  488. END
  489.